<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="demo" class="one two three" title="hello"></div>
</body>

<script>
    function Cat(name, color) {
        // {}

        // 原型属性 -> 所有的实例化对象都有一个原型属性([[Prototype]],__proto__) ->指向构造函数的原型对象(浅复制) -> 所有的实例化对象都可以通过原型属性访问构造函数的原型对象
        // {}[[Prototype]] = Fn.prototype;


        // this -> {}

        // 我们可以做的操作 把需要的属性和方法绑定到实例化对象上
        this.name = name;
        this.color = color;
        // return this;
    }

    // prototype(原型对象) => 存实例化对象公共的属性和方法(构造函数的原型对象)
    // Fn.prototype = {constructor:Fn}
    Cat.prototype.species = "Cat";
    Cat.prototype.call = function () {
        console.log("喵喵");
    }
    Cat.prototype.skill = function () {
        console.log("捉老鼠");
    }

    Cat.prototype.say = function () {
        // this->指向调用此方法的实例化对象 (哪个实例化对象调用它 他就指向谁)
        // console.log("say方法被调用:", this);
        console.log(this.name, this.color);
    }

    // 构造函数Object原型对象上的属性
    Object.prototype.a = 1;
    Object.prototype.b = 2;


    // 原型链(实例化对象的属性和方法查找时,基于原型[[Prototype]]链式查找机制) 
    // Tom -> Cat.prototype -> Object.prototype -> null

    var Tom = new Cat("Tom", "black");
    console.log(Tom);


    // 注意: 所有的实例化对象 都可以访问构造函数Object.prototype上的属性和方法
    // Object原型对象上的方法:
    // toString()  将实例化对象转字符串
    // valueOf()   返回实例化对象的值
    // isPrototypeOf()   判断某个构造函数的原型对象 是否存在于 某个实例化对象的原型链上
    // hasOwnProperty()  判断某个实例化对象上是否存在某个属性(注意:只在实例化对象自身查找,不查原型链)
    // propertyIsEnumerable()


    // valueOf()   返回实例化对象的值
    // var Tom = new Cat("Tom", "black");
    // console.log(Tom.valueOf());

    // var arr = [1, 2, 3];
    // console.log(arr.valueOf());

    // var date = new Date();
    // console.dir(date);
    // console.log(date.valueOf());
    // console.log(Object.prototype.valueOf.call(date));



    // isPrototypeOf()  判断某个构造函数的原型对象 是否存在于 某个实例化对象的原型链上
    // Tom的原型链
    // Tom -> Cat.prototype -> Object.prototype -> null

    // console.log(Cat.prototype.isPrototypeOf(Tom)); // true
    // console.log(Object.prototype.isPrototypeOf(Tom)); // true
    // console.log(Array.prototype.isPrototypeOf(Tom)); // false

    // 拓展
    // instanceOf()     判断某个实例化对象的原型链上 是否存在 某个构造函数 的原型对象
    // console.log(Tom instanceof Cat); // true
    // console.log(Tom instanceof Object); // true

    // var div = document.getElementById("demo");
    // console.dir(div);

    // div ->  HTMLDivElement -> HTMLElement -> Element -> Node -> EventTarget -> Object -> null
    // console.log(div instanceof Element);


    // hasOwnProperty()     判断某个实例化对象上是否存在某个属性(注意:只在实例化对象自身查找,不查原型链)

    // var Tom = new Cat("Tom", "black");
    // console.log(Tom.hasOwnProperty("name")); // true
    // console.log(Tom.hasOwnProperty("color")); // true

    // console.log(Tom.hasOwnProperty("species"));  // false
    // console.log(Tom.hasOwnProperty("a")); // false
    // console.log(Tom.hasOwnProperty("b")); // false


    // 拓展
    // 如何查找实例化对象的原型链上是否存在某个属性?   => in
    // "xxx" in 对象

    // for (var key in Tom) {
    //     console.log(key);
    // }

    // console.log("name" in Tom);// true
    // console.log("color" in Tom);// true
    // console.log("species" in Tom);// true
    // console.log("a" in Tom);// true
    // console.log("b" in Tom);// true

    // console.log("age" in Tom); // false


    // propertyIsEnumerable()  属性是否可遍历 (只查找实例化对象本身)
    // console.log(Tom.propertyIsEnumerable("name")); // true
    // console.log(Tom.propertyIsEnumerable("color")); // true

    // console.log(Tom.propertyIsEnumerable("species")); // flase
    // console.log(Tom.propertyIsEnumerable("a")); // false
    // console.log(Tom.propertyIsEnumerable("b")); // false
</script>

</html>